package com.mapbox.ohos.gestures.testapp;

import com.chinasoft_ohos.commontools.toast.Toast;
import com.mapbox.ohos.gestures.*;
import com.mapbox.ohos.gestures.testapp.slice.MyProvider;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.window.dialog.BaseDialog;
import ohos.agp.window.dialog.PopupDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.multimodalinput.event.TouchEvent;
import ohos.vibrator.agent.VibratorAgent;
import ohos.vibrator.bean.VibrationPattern;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * MainAbility
 *
 * @since 2021-07-29
 */
public class MainAbility extends Ability {
    private Boolean isFristLoadingView = true;
    private Image icon;
    private Button mapboxButton;
    private DependentLayout mutuallyExclusiveSpinner;
    private HelpDialog helpDialog;
    private Text miniHelp;
    private VibratorAgent vibratorAgent;
    private Integer vibratorId;

    private PopupDialog dialog;
    private Slider rotateThresholdProgress;
    private Slider scaleThresholdProgress;

    private OhosGesturesManager ohosGesturesManager;

    private boolean isScrollChosen;

    private final ExclusiveSetSpinnerObject emptyExclusiveSetSpinnerObject = new ExclusiveSetSpinnerObject(-1); // (none)

    private final MoveGestureDetector.OnMoveGestureListener onMoveGestureListener =
        new MoveGestureDetector.OnMoveGestureListener() {
            @Override
            public boolean onMoveBegin(MoveGestureDetector detector) {
                return true;
            }

            @Override
            public boolean onMove(MoveGestureDetector detector, float distanceX, float distanceY) {
                if (icon.getContentPositionX() > 3000) {
                    icon.setContentPositionX(3000);
                }

                if (icon.getContentPositionX() < -3000) {
                    icon.setContentPositionX(-3000);
                }

                if (icon.getContentPositionY() > 3000) {
                    icon.setContentPositionY(3000);
                }

                if (icon.getContentPositionY() < -3000) {
                    icon.setContentPositionY(-2999);
                }
                icon.setTranslationX(icon.getTranslationX() - distanceX);
                icon.setTranslationY(icon.getTranslationY() - distanceY);
                return true;
            }

            @Override
            public void onMoveEnd(MoveGestureDetector detector, float velocityX, float velocityY) {
            }
        };


    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        getWindow().setStatusBarColor(Color.getIntColor("#303E9D"));
        initVibrator();
        setupGesturesManager();
        setupViews();
    }

    @Override
    public void onActive() {
        super.onActive();
        if (isFristLoadingView) {
            icon.setTranslation(getScreenWidth_(this) / 2 - (icon.getWidth() / 2), getScreenHeight_(this) / 2 - (icon.getHeight() / 2));
            icon.invalidate();
            isFristLoadingView = false;
        }
    }

    @Override
    protected void onBackground() {
        super.onBackground();
        helpDialog = null;
    }

    private void setupViews() {
        DependentLayout title = (DependentLayout) findComponentById(ResourceTable.Id_title);
        title.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                return true;
            }
        });
        miniHelp = (Text) findComponentById(ResourceTable.Id_mini_help);
        icon = (Image) findComponentById(ResourceTable.Id_icon);
        Image question = (Image) findComponentById(ResourceTable.Id_question);
        question.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                helpDialog = HelpDialog.newInstance(MainAbility.this);
                helpDialog.setTransparent(true);
                helpDialog.show();
            }
        });
        question.setLongClickedListener(new Component.LongClickedListener() {
            @Override
            public void onLongClicked(Component component) {
                if (miniHelp.getVisibility() == Component.HIDE) {
                    if (hasVibrator()) {
                        startVibrator(100);
                    }
                    miniHelp.setVisibility(Component.VISIBLE);
                    TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();
                    uiTaskDispatcher.delayDispatch(new Runnable() {
                        @Override
                        public void run() {
                            miniHelp.setVisibility(Component.HIDE);
                        }
                    }, 3000);
                }
            }
        });
        mutuallyExclusiveSpinner = (DependentLayout) findComponentById(ResourceTable.Id_spinner_exclusives);
        ArrayList<ExclusiveSetSpinnerObject> list = new ArrayList();
        list.add(emptyExclusiveSetSpinnerObject);
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_SHOVE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_SCALE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_SHOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_SCALE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_QUICK_SCALE,
            OhosGesturesManager.GESTURE_TYPE_MOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL,
            OhosGesturesManager.GESTURE_TYPE_SCALE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL,
            OhosGesturesManager.GESTURE_TYPE_SHOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_SCALE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL,
            OhosGesturesManager.GESTURE_TYPE_SHOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_SCALE,
            OhosGesturesManager.GESTURE_TYPE_MOVE,
            OhosGesturesManager.GESTURE_TYPE_SHOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_ROTATE,
            OhosGesturesManager.GESTURE_TYPE_MOVE));
        list.add(new ExclusiveSetSpinnerObject(OhosGesturesManager.GESTURE_TYPE_SCALE,
            OhosGesturesManager.GESTURE_TYPE_SCROLL,
            OhosGesturesManager.GESTURE_TYPE_SIDEWAYS_SHOVE));

        mutuallyExclusiveSpinner.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                initDialog(list);
                dialog.show();
            }
        });
        mutuallyExclusiveSpinner.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                return true;
            }
        });

        mapboxButton = (Button) findComponentById(ResourceTable.Id_button_mapbox);
        mapboxButton.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                Toast.show("无法链接该应用");
            }
        });
        mapboxButton.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                return true;
            }
        });


        rotateThresholdProgress = (Slider) findComponentById(ResourceTable.Id_progress_threshold_rotate);

        rotateThresholdProgress.setProgressValue((int) ohosGesturesManager.getRotateGestureDetector().getAngleThreshold());
        rotateThresholdProgress.setValueChangedListener(new Slider.ValueChangedListener() {
            @Override
            public void onProgressUpdated(Slider slider, int progress, boolean b) {
                ohosGesturesManager.getRotateGestureDetector().setAngleThreshold(progress);
            }

            @Override
            public void onTouchStart(Slider slider) {
            }

            @Override
            public void onTouchEnd(Slider slider) {
            }
        });

        scaleThresholdProgress = (Slider) findComponentById(ResourceTable.Id_progress_threshold_scale);
        scaleThresholdProgress.setProgressValue((int) ohosGesturesManager.getStandardScaleGestureDetector().getSpanSinceStartThreshold());

        scaleThresholdProgress.setValueChangedListener(new Slider.ValueChangedListener() {
            @Override
            public void onProgressUpdated(Slider slider, int progress, boolean b) {
                ohosGesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(progress);
            }

            @Override
            public void onTouchStart(Slider slider) {
            }

            @Override
            public void onTouchEnd(Slider slider) {
            }
        });

        DirectionalLayout blowView = (DirectionalLayout) findComponentById(ResourceTable.Id_dir_blow_view);
        blowView.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                return true;
            }
        });
    }

    private void initDialog(List<ExclusiveSetSpinnerObject> list) {
        Component mDialogComponent = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_layout_spinner, null, false);
        mDialogComponent.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                return true;
            }
        });
        ListContainer listContainer = (ListContainer) mDialogComponent.findComponentById(ResourceTable.Id_lc_spinner);
        dialog = new PopupDialog(this, mutuallyExclusiveSpinner, 700, listContainer.getHeight());
        dialog.setCustomComponent(mDialogComponent);
        listContainer.setLongClickable(false);
        MyProvider provider = new MyProvider(this, list);
        provider.setItemClick(new MyProvider.ItemClick() {
            @Override
            public void itemClick(Component component, int position) {
                ExclusiveSetSpinnerObject exclusiveSetSpinnerObject = list.get(position);

                if (exclusiveSetSpinnerObject.equals(emptyExclusiveSetSpinnerObject)) {
                    ohosGesturesManager.setMutuallyExclusiveGestures(new ArrayList<Set<Integer>>());
                } else {
                    Set<Integer> exclusiveSet = exclusiveSetSpinnerObject.getExclusiveSet();
                    ohosGesturesManager.setMutuallyExclusiveGestures(exclusiveSetSpinnerObject.getExclusiveSet());
                    if (exclusiveSet.contains(OhosGesturesManager.GESTURE_TYPE_SCROLL)) {
                        isScrollChosen = true;
                        ohosGesturesManager.removeMoveGestureListener();
                    } else if (exclusiveSet.contains(OhosGesturesManager.GESTURE_TYPE_MOVE)) {
                        isScrollChosen = false;
                        ohosGesturesManager.setMoveGestureListener(onMoveGestureListener);
                    }
                }

                ((Text) mutuallyExclusiveSpinner.findComponentById(ResourceTable.Id_text_spinner)).setText(list.get(position).toString());
                dialog.destroy();
            }
        });
        listContainer.setItemProvider(provider);
        listContainer.setCanAcceptScrollListener((component, i, b) -> false);
        dialog.setTransparent(true);
        dialog.setDialogListener(new BaseDialog.DialogListener() {
            @Override
            public boolean isTouchOutside() {
                if (dialog != null) {
                    dialog.destroy();
                }
                return false;
            }
        });
    }

    private void setupGesturesManager() {
        ohosGesturesManager = new OhosGesturesManager(this);

        ohosGesturesManager.setStandardScaleGestureListener(
            new StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener() {

                @Override
                public boolean onScale(StandardScaleGestureDetector detector) {
                    rescaleIcon(detector.getScaleFactor());
                    return true;
                }
            });

        ohosGesturesManager.setRotateGestureListener(new RotateGestureDetector.SimpleOnRotateGestureListener() {
            @Override
            public boolean onRotate(RotateGestureDetector detector, float rotationDegreesSinceLast,
                                    float rotationDegreesSinceFirst) {
                float rotation = icon.getRotation();
                icon.setRotation(rotation - rotationDegreesSinceLast);
                return true;
            }
        });

        ohosGesturesManager.setStandardGestureListener(new StandardGestureDetector.SimpleStandardOnGestureListener() {
            @Override
            public boolean onScroll(TouchEvent e1, TouchEvent e2, float distanceX, float distanceY) {
                if (isScrollChosen) {
                    icon.setTranslationX(icon.getTranslationX() - distanceX);
                    icon.setTranslationY(icon.getTranslationY() - distanceY);
                    return true;
                }
                return false;
            }

            @Override
            public boolean onDoubleTap(TouchEvent touchEvent) {
                rescaleIcon(1.40f);
                return true;
            }
        });

        ohosGesturesManager.setMultiFingerTapGestureListener(
            new MultiFingerTapGestureDetector.OnMultiFingerTapGestureListener() {
                @Override
                public boolean onMultiFingerTap(MultiFingerTapGestureDetector detector, int pointersCount) {
                    if (pointersCount == 2) {
                        rescaleIcon(0.65f);
                    }
                    return true;
                }
            });

        ohosGesturesManager.setShoveGestureListener(new ShoveGestureDetector.SimpleOnShoveGestureListener() {
            @Override
            public boolean onShove(ShoveGestureDetector detector, float deltaPixelsSinceLast, float deltaPixelsSinceStart) {
                icon.setRotation(deltaPixelsSinceLast);
                return true;
            }
        });

        ohosGesturesManager.setSidewaysShoveGestureListener(
            new SidewaysShoveGestureDetector.SimpleOnSidewaysShoveGestureListener() {
                @Override
                public boolean onSidewaysShove(SidewaysShoveGestureDetector detector, float deltaPixelsSinceLast, float deltaPixelsSinceStart) {
                    icon.setRotation(deltaPixelsSinceLast);
                    return true;
                }
            });

        ohosGesturesManager.setMoveGestureListener(onMoveGestureListener);
    }

    private void rescaleIcon(float scaleFactor) {
        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(this.getContext());
        Point pt = new Point();
        display.get().getSize(pt);
        ComponentContainer.LayoutConfig layoutConfig = icon.getLayoutConfig();
        int width = (int) (layoutConfig.width * scaleFactor);
        int height = (int) (layoutConfig.height * scaleFactor);
        if (width > 100 && height > 100 && width < pt.getPointX() && height < pt.getPointY()) {
            layoutConfig.width = width;
            layoutConfig.height = height;
            icon.setLayoutConfig(layoutConfig);
            icon.setPivot(icon.getLocationOnScreen()[0] + (icon.getWidth() / 2), icon.getLocationOnScreen()[1] + (icon.getHeight() / 2));
        }
    }

    @Override
    protected boolean onTouchEvent(TouchEvent event) {
        return ohosGesturesManager.onTouchEvent(event) || super.onTouchEvent(event);
    }


    private int getScreenHeight_(Context act) {
        int density = act.getResourceManager().getDeviceCapability().screenDensity / 160;
        int height = act.getResourceManager().getDeviceCapability().height;
        return density * height;
    }

    private int getScreenWidth_(Context act) {
        int density = act.getResourceManager().getDeviceCapability().screenDensity / 160;
        int width = act.getResourceManager().getDeviceCapability().width;
        return density * width;
    }

    private void initVibrator() {
        vibratorAgent = new VibratorAgent();
        List<Integer> vibratorList = vibratorAgent.getVibratorIdList();
        if (vibratorList.isEmpty()) {
            vibratorAgent = null;
            return;
        }
        vibratorId = vibratorList.get(0);
    }

    private boolean hasVibrator() {
        boolean isSupport = vibratorAgent.isEffectSupport(vibratorId, VibrationPattern.VIBRATOR_TYPE_CAMERA_CLICK);
        return isSupport;
    }

    private void startVibrator(int time) {
        vibratorAgent.startOnce(vibratorId, time);
    }
}
